package org.moonlight.jvm.natives.java.lang.system;

import org.moonlight.jvm.natives.AbstractNativeMethod;
import org.moonlight.jvm.rtda.exclusive.Frame;
import org.moonlight.jvm.rtda.exclusive.LocalVars;
import org.moonlight.jvm.rtda.share.Object;
import org.moonlight.jvm.rtda.share.heap.Class;

/**
 * java.lang.System public static native void arraycopy(Object src,  int  srcPos,
 *                                         Object dest, int destPos,
 *                                         int length);
 *
 * @author Moonlight
 * @createTime 2023/9/22 14:05
 **/
public class ArrayCopy extends AbstractNativeMethod {

    public ArrayCopy() {
        super("java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
    }

    @Override
    public void nativeMethod(Frame frame) {
        // 局部变量表
        LocalVars localVars = frame.getLocalVars();
        // ayyaycopy 所需的参数
        Object src = localVars.getRef(0);
        int srcPos = localVars.getInt(1);
        Object dest = localVars.getRef(2);
        int destPos = localVars.getInt(3);
        int length = localVars.getInt(4);

        if (src == null || dest == null) {
            throw new NullPointerException();
        }
        if (!checkArrayCopy(src, dest)) {
            throw new ArrayStoreException();
        }
        if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > src.arrayLength() || destPos + length > dest.arrayLength()) {
            throw new ArrayIndexOutOfBoundsException();
        }

        doArrayCopy(src, dest, srcPos, destPos, length);
    }

    private void doArrayCopy(Object src, Object dest, int srcPos, int destPos, int length) {
        System.out.println("走的是doArrayCopy");

        if (src.getData() instanceof byte[]) {
            System.arraycopy(src.bytes(), srcPos, dest.bytes(), destPos, length);
        } else if (src.getData() instanceof char[]) {
            System.arraycopy(src.chars(), srcPos, dest.chars(), destPos, length);
        } else if (src.getData() instanceof short[]) {
            System.arraycopy(src.shorts(), srcPos, dest.shorts(), destPos, length);
        } else if (src.getData() instanceof int[]) {
            System.arraycopy(src.ints(), srcPos, dest.ints(), destPos, length);
        } else if (src.getData() instanceof float[]) {
            System.arraycopy(src.floats(), srcPos, dest.floats(), destPos, length);
        } else if (src.getData() instanceof double[]) {
            System.arraycopy(src.doubles(), srcPos, dest.doubles(), destPos, length);
        } else if (src.getData() instanceof long[]) {
            System.arraycopy(src.longs(), srcPos, dest.longs(), destPos, length);
        } else if (src.getData() instanceof Object[]) {
            System.arraycopy(src.refs(), srcPos, dest.refs(), destPos, length);
        } else {
            throw new RuntimeException("Not array");
        }
    }

    private boolean checkArrayCopy(Object src, Object dest) {
        Class srcClazz = src.getClazz();
        Class destClazz = dest.getClazz();

        if (!srcClazz.isArray() || !destClazz.isArray()) {
            return false;
        }

        if (srcClazz.componentClass().isPrimitive() || destClazz.componentClass().isPrimitive()) {
            return srcClazz.equals(destClazz);
        }

        return true;
    }

}